package com.ccp.dev.workflow.listener;

import com.ccp.dev.core.basic.engine.GroovyScriptEngine;
import com.ccp.dev.core.util.AppUtil;
import com.ccp.dev.core.util.StringUtil;
import com.ccp.dev.workflow.bpmconst.BpmConst;
import com.ccp.dev.workflow.model.BpmNodeScript;
import com.ccp.dev.workflow.model.FlowNodeInfo;
import com.ccp.dev.workflow.model.NodeCache;
import com.ccp.dev.workflow.service.BpmNodeScriptService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.delegate.BaseExecutionListener;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.ExecutionListener;
import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
import org.flowable.engine.runtime.Execution;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;

/**
 * ClassDescribe:
 * 节点事件基类， 采用了模板模式
 *
 * @author :wangcheng
 * Date: 2019-05-13
 */
public abstract class BaseNodeEventListener implements ExecutionListener {
    private static final Logger LOGGER = LoggerFactory.getLogger(BaseNodeEventListener.class);
    @Resource
    private RuntimeService runtimeService;
    @Override
    public void notify(DelegateExecution execution){
        LOGGER.debug("enter the node event listener..{}", execution.getId());
        ExecutionEntity entity = (ExecutionEntity) execution;
        //act_re_procdef表对应的流程定义id
        String procDefId = entity.getProcessDefinitionId();
        //活动节点id
        String nodeId = "";

        String eventName = execution.getEventName();
        if(BaseExecutionListener.EVENTNAME_START.equals(eventName)){
            nodeId = entity.getActivityId();
            if (StringUtil.isEmpty(nodeId)) {
                nodeId = entity.getStartActivityId();
            }
        }else if(BaseExecutionListener.EVENTNAME_END.equals(eventName)){
            List<Execution>  executionList = runtimeService.createExecutionQuery().processInstanceId(execution.getProcessInstanceId()).list();
            for (Execution exe:executionList) {
                if(!exe.getId().equals(execution.getProcessInstanceId())){
                    nodeId = exe.getActivityId();
                    break;
                }
            }
        }

        if(StringUtil.isEmpty(nodeId)){
            return;
        }

        // 执行实现类业务逻辑
        execute(execution, procDefId, nodeId);

        // 只有节点不为空时，才会去执行脚本
        if (nodeId != null) {
            // 获取事件类型
            Integer scriptType = getScriptType();
            //执行事件脚本
            exeEventScript(execution,scriptType,procDefId,nodeId);
        }
    }

    /**
     * 获取脚本类型
     *
     * @return 脚本类型代码
     */
    protected abstract Integer getScriptType();

    /**
     * 实行子类的逻辑事务
     *
     * @param execution           执行实例
     * @param procDefId 流程定义id
     * @param nodeId          活动节点id
     */
    protected abstract void execute(DelegateExecution execution, String procDefId, String nodeId);

    /**
     * 执行脚本事件
     *
     * @param execution           执行实列
     * @param scriptType          脚本类型
     * @param procDefId            流程定义id
     * @param nodeId              活动节点id
     */
    private void exeEventScript(DelegateExecution execution, int scriptType, String procDefId, String nodeId) {
        BpmNodeScriptService bpmNodeScriptService=(BpmNodeScriptService)AppUtil.getBean("bpmNodeScriptService");
        BpmNodeScript scriptModel=bpmNodeScriptService.getScriptByType(nodeId, procDefId, scriptType);
        if(scriptModel==null){
            return;
        }
        //脚本
        String script=scriptModel.getScript();
        if(StringUtil.isEmpty(script)){
            return;
        }
        GroovyScriptEngine scriptEngine=AppUtil.getBean(GroovyScriptEngine.class);
        Map<String, Object> vars=execution.getVariables();
        vars.put("execution", execution);
        scriptEngine.execute(script, vars);
        LOGGER.debug("execution script :" + script);
    }
}
